// initialize cross-window stateful counter
window.addEventListener("load", function() {MyToolbar.init();}, false);
window.addEventListener("load", function() {MyToolbar.bindDDL();}, false);

//START INSERTION


var myExtension = {
    oldURL: null,

    init: function() {
        gBrowser.addProgressListener(this);
    },

    uninit: function() {
        gBrowser.removeProgressListener(this);
    },

    processNewURL: function(aURI) {
        if (aURI.spec == this.oldURL) return;

        // now we know the url is new...
		if (aURI.spec.substring(0,5) != 'about')
			alert(aURI.spec);
			
		test(aURI.spec);
        
		this.oldURL = aURI.spec;
    },

    // nsIWebProgressListener
    QueryInterface: XPCOMUtils.generateQI(["nsIWebProgressListener",
                                           "nsISupportsWeakReference",
										   "nsISupports"]),

    onLocationChange: function(aProgress, aRequest, aURI) {
        this.processNewURL(aURI);
		
    },

    onStateChange: function() {},
    onProgressChange: function() {},
    onStatusChange: function() {},
    onSecurityChange: function(aWebProgress, aRequest, aState) 
    {
        // check if the state is secure or not
        if(aState & Components.interfaces.nsIWebProgressListener.STATE_IS_SECURE)
        {
            // this is a secure page, check if aRequest is a channel,
            // since only channels have security information
            if (aRequest instanceof Components.interfaces.nsIChannel)
            {
                alertSecurityInfo(aRequest);
            }
        }    
    }
};

window.addEventListener("load", function() { myExtension.init() }, false);
window.addEventListener("unload", function() { myExtension.uninit() }, false);


function alertSecurityInfo(channel) {

    // Do we have a valid channel argument?
    if (! channel instanceof  Components.interfaces.nsIChannel) {
        alert("No channel available\n");
        return;
    }

    var secInfo = channel.securityInfo;

    // Print general connection security state
    if (secInfo instanceof Components.interfaces.nsITransportSecurityInfo) {
/*
        // Check security state flags
        if ((secInfo.securityState & Components.interfaces.nsIWebProgressListener.STATE_IS_SECURE) == Components.interfaces.nsIWebProgressListener.STATE_IS_SECURE)
            alert("secure\n");

        else if ((secInfo.securityState & Components.interfaces.nsIWebProgressListener.STATE_IS_INSECURE) == Components.interfaces.nsIWebProgressListener.STATE_IS_INSECURE)
            alert("insecure\n");

        else if ((secInfo.securityState & Components.interfaces.nsIWebProgressListener.STATE_IS_BROKEN) == Components.interfaces.nsIWebProgressListener.STATE_IS_BROKEN)
            alert("unknown\n");

        alert("\tSecurity description: " + secInfo.QueryInterface(Components.interfaces.nsITransportSecurityInfo).shortSecurityDescription + "\n");
        alert("\tSecurity error message: " + secInfo.QueryInterface(Components.interfaces.nsITransportSecurityInfo).errorMessage + "\n");
		
		*/
    }
    else {

        alert("\tNo security info available for this channel\n");
    }

    // Print SSL certificate details
    if (secInfo instanceof Components.interfaces.nsISSLStatusProvider) {

        var cert = secInfo.QueryInterface(Components.interfaces.nsISSLStatusProvider).SSLStatus.QueryInterface(Components.interfaces.nsISSLStatus).serverCert;
		
        displayCert(cert,false);
	
		
		/*
		alert("This cert: " + btoa(result));
		
	    alert("\tCommon name (CN) = " + cert.commonName + "\n");
        alert("\tOrganisation = " + cert.organization + "\n");
        alert("\tIssuer = " + cert.issuerOrganization + "\n");
        alert("\tSHA1 fingerprint = " + cert.sha1Fingerprint + "\n");
		*/

        var verificationResult = cert.verifyForUsage(Components.interfaces.nsIX509Cert.CERT_USAGE_SSLServer);
        alert("\tVerification: ");

        switch (verificationResult) {
            case Components.interfaces.nsIX509Cert.VERIFIED_OK:
                alert("OK");
                break;
            case Components.interfaces.nsIX509Cert.NOT_VERIFIED_UNKNOWN:
                alert("not verfied/unknown");
                break;
            case Components.interfaces.nsIX509Cert.CERT_REVOKED:
                alert("revoked");
                break;
            case Components.interfaces.nsIX509Cert.CERT_EXPIRED:
                alert("expired");
                break;
            case Components.interfaces.nsIX509Cert.CERT_NOT_TRUSTED:
                alert("not trusted");
                break;
            case Components.interfaces.nsIX509Cert.ISSUER_NOT_TRUSTED:
                alert("issuer not trusted");
                break;
            case Components.interfaces.nsIX509Cert.ISSUER_UNKNOWN:
                alert("issuer unknown");
                break;
            case Components.interfaces.nsIX509Cert.INVALID_CA:
                alert("invalid CA");
                break;
            default:
                alert("unexpected failure");
                break;
        }
        alert("\n");

        alert("\tCommon name (CN) = " + cert.commonName + "\n");
        alert("\tOrganisation = " + cert.organization + "\n");
        alert("\tIssuer = " + cert.issuerOrganization + "\n");
        alert("\tSHA1 fingerprint = " + cert.sha1Fingerprint + "\n");

        var validity = cert.validity.QueryInterface(Components.interfaces.nsIX509CertValidity);
        alert("\tValid from " + validity.notBeforeGMT + "\n");
        alert("\tValid until " + validity.notAfterGMT + "\n");
    }
}

function displayCert(cert,isActive)
{
		var len = new Object();
        var derData = cert.getRawDER(len);
        let result = "";
        for (let j = 0, dataLength = derData.length; j < dataLength; ++j)
		   {
           result += String.fromCharCode(derData[j]);
		   }
		   
		var pem_str = btoa(result);
		var base64_pem_str = "-----BEGIN CERTIFICATE-----\n";
		
		for (let k = 0; k < pem_str.length; k++)
		{
		 base64_pem_str += pem_str[k];
		 if (k%64==63)
		 {
			base64_pem_str += "\n"; 
		 }
		}
		
		base64_pem_str += "\n-----END CERTIFICATE-----";
		if (isActive)
		    alert ("Active mode certificate \n" + base64_pem_str);
		else
			alert ("Certificate \n" + base64_pem_str);
}
// Active mode: obtain a cert when available.

let Cc = Components.classes;
let Ci = Components.interfaces;

function createTCPErrorFromFailedXHR(xhr) {
  let status = xhr.channel.QueryInterface(Ci.nsIRequest).status;

  let errType;
  if ((status & 0xff0000) === 0x5a0000) { // Security module
    const nsINSSErrorsService = Ci.nsINSSErrorsService;
    let nssErrorsService = Cc['@mozilla.org/nss_errors_service;1'].getService(nsINSSErrorsService);
    let errorClass;
    // getErrorClass will throw a generic NS_ERROR_FAILURE if the error code is
    // somehow not in the set of covered errors.
    try {
      errorClass = nssErrorsService.getErrorClass(status);
    } catch (ex) {
      errorClass = 'SecurityProtocol';
    }
    if (errorClass == nsINSSErrorsService.ERROR_CLASS_BAD_CERT) {
      errType = 'SecurityCertificate';
    } else {
      errType = 'SecurityProtocol';
    }
                 
    // NSS_SEC errors (happen below the base value because of negative vals)
    if ((status & 0xffff) < Math.abs(nsINSSErrorsService.NSS_SEC_ERROR_BASE)) {
      // The bases are actually negative, so in our positive numeric space, we
      // need to subtract the base off our value.
      let nssErr = Math.abs(nsINSSErrorsService.NSS_SEC_ERROR_BASE)
                       - (status & 0xffff);
      switch (nssErr) {
        case 11: // SEC_ERROR_EXPIRED_CERTIFICATE, sec(11)
          errName = 'SecurityExpiredCertificateError';
          break;
        case 12: // SEC_ERROR_REVOKED_CERTIFICATE, sec(12)
          errName = 'SecurityRevokedCertificateError';
          break;
          
        // per bsmith, we will be unable to tell these errors apart very soon,
        // so it makes sense to just folder them all together already.
        case 13: // SEC_ERROR_UNKNOWN_ISSUER, sec(13)
        case 20: // SEC_ERROR_UNTRUSTED_ISSUER, sec(20)
        case 21: // SEC_ERROR_UNTRUSTED_CERT, sec(21)
        case 36: // SEC_ERROR_CA_CERT_INVALID, sec(36)
          errName = 'SecurityUntrustedCertificateIssuerError';
          break;
        case 90: // SEC_ERROR_INADEQUATE_KEY_USAGE, sec(90)
          errName = 'SecurityInadequateKeyUsageError';
          break;
        case 176: // SEC_ERROR_CERT_SIGNATURE_ALGORITHM_DISABLED, sec(176)
          errName = 'SecurityCertificateSignatureAlgorithmDisabledError';
          break;
        default:
          errName = 'SecurityError';
          break;
      }
    } else {
      let sslErr = Math.abs(nsINSSErrorsService.NSS_SSL_ERROR_BASE)
                       - (status & 0xffff);
      switch (sslErr) {
        case 3: // SSL_ERROR_NO_CERTIFICATE, ssl(3)
          errName = 'SecurityNoCertificateError';
          break;
        case 4: // SSL_ERROR_BAD_CERTIFICATE, ssl(4)
          errName = 'SecurityBadCertificateError';
          break;
        case 8: // SSL_ERROR_UNSUPPORTED_CERTIFICATE_TYPE, ssl(8)
          errName = 'SecurityUnsupportedCertificateTypeError';
          break;
        case 9: // SSL_ERROR_UNSUPPORTED_VERSION, ssl(9)
          errName = 'SecurityUnsupportedTLSVersionError';
          break;
        case 12: // SSL_ERROR_BAD_CERT_DOMAIN, ssl(12)
          errName = 'SecurityCertificateDomainMismatchError';
          break;
        default:
          errName = 'SecurityError';
          break;
      }
    }
  } else {
    errType = 'Network';
    switch (status) {
      // connect to host:port failed
      case 0x804B000C: // NS_ERROR_CONNECTION_REFUSED, network(13)
        errName = 'ConnectionRefusedError';
        break;
      // network timeout error
      case 0x804B000E: // NS_ERROR_NET_TIMEOUT, network(14)
        errName = 'NetworkTimeoutError';
        break;
      // hostname lookup failed
      case 0x804B001E: // NS_ERROR_UNKNOWN_HOST, network(30)
        errName = 'DomainNotFoundError';
        break;
      case 0x804B0047: // NS_ERROR_NET_INTERRUPT, network(71)
        errName = 'NetworkInterruptError';
        break;
      default:
        errName = 'NetworkError';
        break;
    }
  }

  // XXX we have no TCPError implementation right now because it's really hard to
  // do on b2g18. On mozilla-central we want a proper TCPError that ideally
  // sub-classes DOMError. Bug 867872 has been filed to implement this and
  // contains a documented TCPError.webidl that maps all the error codes we use in
  // this file to slightly more readable explanations.
  let error = Cc["@mozilla.org/dom-error;1"].createInstance(Ci.nsIDOMDOMError);
  error.wrappedJSObject.init(errName);
  return error;
 
  // XXX: errType goes unused
}

function dumpSecurityInfo(xhr, error) {
  let channel = xhr.channel;
 
  try {
    dump("Connection status:\n");
    if (!error) {
      dump("\tsucceeded\n");
    } else {
      alert("\t Active connection failed: " + error.name + "\n");
    }
 
    let secInfo = channel.securityInfo;
    // Print general connection security state
    dump("Security Info:\n");
    if (secInfo instanceof Ci.nsITransportSecurityInfo) {
      secInfo.QueryInterface(Ci.nsITransportSecurityInfo);
      dump("\tSecurity state: ");
        // Check security state flags
    if ((secInfo.securityState & Ci.nsIWebProgressListener.STATE_IS_SECURE)
           == Ci.nsIWebProgressListener.STATE_IS_SECURE) {
      dump("secure\n");
    } else if ((secInfo.securityState & Ci.nsIWebProgressListener.STATE_IS_INSECURE)
           == Ci.nsIWebProgressListener.STATE_IS_INSECURE) {
      dump("insecure\n");
    } else if ((secInfo.securityState & Ci.nsIWebProgressListener.STATE_IS_BROKEN)
               == Ci.nsIWebProgressListener.STATE_IS_BROKEN) {
      dump("unknown\n");
      dump("\tSecurity description: " + secInfo.shortSecurityDescription + "\n");
      dump("\tSecurity error message: " + secInfo.errorMessage + "\n");
    }
    } else {
      dump("\tNo security info available for this channel\n");
    }

    // Print SSL certificate details
    if (secInfo instanceof Ci.nsISSLStatusProvider) {
      var cert = secInfo.QueryInterface(Ci.nsISSLStatusProvider)
                        .SSLStatus.QueryInterface(Ci.nsISSLStatus).serverCert;
						
	displayCert(cert,true);
            
      dump("\tCommon name (CN) = " + cert.commonName + "\n");
      dump("\tOrganisation = " + cert.organization + "\n");
      dump("\tIssuer = " + cert.issuerOrganization + "\n");
      dump("\tSHA1 fingerprint = " + cert.sha1Fingerprint + "\n");
       
      var validity = cert.validity.QueryInterface(Ci.nsIX509CertValidity);
      dump("\tValid from " + validity.notBeforeGMT + "\n");
      dump("\tValid until " + validity.notAfterGMT + "\n");
    }
  } catch(err) {
    alert(err);
  }
}

function test(url) {
  var req = Components.classes["@mozilla.org/xmlextras/xmlhttprequest;1"].createInstance();
  req.open('GET', url, true);
  req.addEventListener("error",
                       function(e) {
                         var error = createTCPErrorFromFailedXHR(req);
                         dumpSecurityInfo(req, error);
                       },
                       false);
 
  req.onload = function(e) {
    dumpSecurityInfo(req);
  };

  req.send();
}


//END INSERTION

var MyToolbar ={
init: function(){
try{

var file = Components.classes["@mozilla.org/file/directory_service;1"].
           getService(Components.interfaces.nsIProperties).
           get("ProfD", Components.interfaces.nsIFile);
file.append("LocalCerts.sqlite");

if (file.exists())
{
alert("Local database already exists...");
return;
}

var storageService = Components.classes["@mozilla.org/storage/service;1"].getService(Components.interfaces.mozIStorageService);

var dbConn = storageService.openDatabase(file); // Will also create the file if it does not exist

dbConn.executeSimpleSQL('CREATE TABLE "Categories" ("CatID" INTEGER PRIMARY KEY NOT NULL  DEFAULT (null) ,"CatName" VARCHAR NOT NULL  DEFAULT (null))');

dbConn.executeSimpleSQL('INSERT INTO Categories (CatName) VALUES("Work")');
dbConn.executeSimpleSQL('INSERT INTO Categories (CatName) VALUES("Bank")');
dbConn.executeSimpleSQL('INSERT INTO Categories (CatName) VALUES("Risky")');
dbConn.executeSimpleSQL('INSERT INTO Categories (CatName) VALUES("Other")');

dbConn.executeSimpleSQL('CREATE TABLE "Certificates" ("CertID" INTEGER PRIMARY KEY NOT NULL , "CertStr" VARCHAR NOT NULL )');

dbConn.executeSimpleSQL('CREATE TABLE "Classification" ("ClickID" INTEGER PRIMARY KEY NOT NULL , "ReportedCat" INTEGER, "CorrectedCat" INTEGER)');

dbConn.executeSimpleSQL('CREATE TABLE "ClickRecords" ("ClickID" INTEGER PRIMARY KEY NOT NULL , "UserID" INTEGER NOT NULL , "DomainID" INTEGER NOT NULL , "FirstLevel" VARCHAR, "Timestamp" DATETIME NOT NULL , "isHTTPS" BOOL NOT NULL , "hasCert" BOOL NOT NULL , "CertID" INTEGER)');

dbConn.executeSimpleSQL('CREATE TABLE "Departments" ("DeptID" INTEGER PRIMARY KEY NOT NULL , "DeptName" VARCHAR NOT NULL )');

dbConn.executeSimpleSQL('CREATE TABLE "Domains" ("DomainID" INTEGER PRIMARY KEY NOT NULL , "DomainName" VARCHAR NOT NULL )');

dbConn.executeSimpleSQL('CREATE TABLE "LabeledWorkSites" ("StaffID" INTEGER NOT NULL , "DomainID" VARCHAR NOT NULL , "DeptID" INTEGER)');

dbConn.close();

alert("Local Database Created.");

}
catch (e)
{alert(e);}},

bindDDL: function()
{
document.getElementById("ddlCategory").setAttribute("datasources","profile:LocalCerts.sqlite");

document.getElementById("ddlCategory").builder.rebuild();
}};